import {InstanceType} from 'typegoose'
import {GameActivityModel} from "../../database/models/gameActivity";
import {ConsumeRecordModel} from '../../database/models/consumeRecord';
import {GamePrizeModel} from "../../database/models/gamePrize";
import {Player, PlayerModel} from "../../database/models/player";
import {Product, ProductModel} from "../../database/models/Product";
import {ProductGroup, ProductGroupModel} from "../../database/models/ProductGroup";
import {expect, requestToApiServer, setupTestEnv, tearDownTestEnv} from './helper';

describe('游戏——扭蛋', () => {

  let player: InstanceType<Player> = null
  let product: InstanceType<Product> = null
  let group: InstanceType<ProductGroup> = null
  let lucky: InstanceType<ProductGroup> = null
  let jwt: string = null

  before(async () => {
    const env = await setupTestEnv()

    player = env.player
    product = env.product
    jwt = env.jwt
    group = env.productGroup
    lucky = env.luckyGroup
  })

  after(async () => {
    await tearDownTestEnv()
  })

  afterEach(async () => {
    return await GamePrizeModel.deleteMany({})
  })

  function draw(time: number) {
    return requestToApiServer()
      .post(`/game/eggdraw/${group._id}`)
      .set({'x-jwt': jwt})
      .send({draws: time})
  }

  it('开始一次扭蛋游戏 扭1次', async function () {
    const playerBefore = await PlayerModel.findOne({_id: player.id});

    const cost = group.priceInGem

    await draw(1)
      .expect(200)
      .then(async res => {
        expect(res.body).have.properties({ok: true})
        expect(res.body.data.prizes).to.have.lengthOf(1)
      })

    const playerAfter = await PlayerModel.findOne({_id: player.id})
    expect(playerAfter.gem).to.equal(playerBefore.gem - cost)
    expect(playerAfter.point).to.equal(playerBefore.point + cost)

    expect(await GamePrizeModel.find({player})).to.have.lengthOf(1)

    const cr = await ConsumeRecordModel.findOne({objectId: group.id, player: player._id})
    expect(cr.gem).to.equal(cost)
  });

  it('开始一次幸运盒子游戏 扭1次', async function () {
    const playerBefore = await PlayerModel.findOne({_id: player.id});

    const cost = lucky.priceInGem

    await requestToApiServer()
      .post(`/game/luckBoxResult/${lucky.id}`) // random objectId
      .set({'x-jwt': jwt})
      .send({draws: 1})
      .then(async res => {
        expect(res.body).have.properties({ok: true})
        expect(res.body.data.prizes).to.have.lengthOf(1)
      })

    const playerAfter = await PlayerModel.findOne({_id: player.id})
    expect(playerAfter.gem).to.equal(playerBefore.gem - cost)
    expect(playerAfter.point).to.equal(playerBefore.point + cost)

    expect(await GamePrizeModel.find({player})).to.have.lengthOf(1)

    const cr = await ConsumeRecordModel.findOne({objectId: group.id, player: player._id})
    expect(cr.gem).to.equal(cost)
  });

  it('开始一次扭蛋游戏 扭10次', async () => {
    await PlayerModel.findByIdAndUpdate(player.id, {$set: {gem: group.priceInGem * 11}})

    await draw(10)
      .expect(200)
      .then(res => {
        expect(res.body).to.have.properties({ok: true})
        expect(res.body.data.prizes).to.have.lengthOf(10)
      })
  })

  it('无效的 group id', async function () {
    const playerBefore = await PlayerModel.findOne({_id: player.id});

    await requestToApiServer()
      .post(`/game/eggdraw/5c88af500a8080682d4665ec`) // random objectId
      .set({'x-jwt': jwt})
      .send({draws: 1})
      .expect(200)
      .then(async res => {
        expect(res.body).have.properties({ok: false, error: 'NO_SUCH_PRODUCT_GROUP'})

      })

    const playerAfter = await PlayerModel.findOne({_id: player.id})
    expect(playerAfter.gem).to.equal(playerBefore.gem)
  })

  it('开始一次扭蛋游戏 扭10次 小奖品无库存', async () => {
    await PlayerModel.findByIdAndUpdate(player.id, {$set: {gem: group.priceInGem * 11}})
    const pg = await ProductGroupModel.findById(group.id).populate(`level4`)
    for (const it of pg.level4 as Array<InstanceType<Product>>) {
      await ProductModel.findByIdAndUpdate(it, {$set: {stock: 0}})
    }

    let stockBefore = 0
    for (const it of (await ProductModel.find().lean())) {
      stockBefore += it.stock
    }

    await draw(10)
      .expect(200)
      .then(res => {
        expect(res.body).to.have.properties({ok: false})
      })

    let stockAfter = 0
    for (const it of (await ProductModel.find().lean())) {
      stockAfter += it.stock
    }
    expect(stockBefore).to.equal(stockAfter)
  })
})
